package com.ybear.ybcomponent.widget.dialog

import android.app.Activity
import android.app.Application
import android.app.Application.ActivityLifecycleCallbacks
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import androidx.arch.core.util.Function
import androidx.core.util.Consumer
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentTransaction
import java.lang.ref.WeakReference
import java.util.Queue
import java.util.concurrent.LinkedBlockingQueue

/**
 * Dialog队列弹出
 */
open class DialogQueue private constructor() : DialogInterface.OnDismissListener {
    companion object {
        private val mDialogQueue: Queue<QueueBean> = LinkedBlockingQueue()
        private var lastShowState = false
        @JvmStatic
        private val i: DialogQueue by lazy { DialogQueue() }
        @JvmStatic
        fun get(): DialogQueue { return i }
    }

    private var mCurrentQueueBean: QueueBean? = null
    private var mOnDialogQueueChangedListener: Consumer<Int>? = null
    private var mWrFragmentTransaction: WeakReference<FragmentTransaction>? = null
    private var mOnInterceptShowByDialogOptionListener: Function<DialogOption, Boolean>? = null
    private var mOnInterceptShowByDialogListener: Function<Dialog, Boolean>? = null
    private var mOnInterceptShowByDialogFragmentListener: Function<DialogFragment, Boolean>? = null
    private var mOnDialogLifecycleListener: OnDialogLifecycleListener? = null
    private var mState = 1 //-1: 强制暂停队列, 0: 暂停队列, 1: 恢复队列

    private class QueueBean {
        private var dop: DialogOption? = null
        private var dialog: Dialog? = null
        private var dialogFragmentX: DialogFragment? = null

        constructor(dop: DialogOption) { this.dop = dop }

        constructor(dialog: Dialog) { this.dialog = dialog }

        constructor(dialog: DialogFragment) { dialogFragmentX = dialog }

        val id: Int get() {
            val obj = get() ?: return 0
            return if (obj is DialogOption) obj.id else obj.hashCode()
        }

        fun get(): Any? {
            if ( dop != null ) return dop
            if ( dialog != null ) return dialog
            return if ( dialogFragmentX != null ) dialogFragmentX else null
        }
    }

    /**
     * 初始化后可以动态监听Activity的生命周期，如果使用了队列，则pause时不会触发队列，resume之后重启队列
     */
    fun initLifecycle(app: Application?): DialogQueue {
        app?.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
            override fun onActivityStarted(activity: Activity) {}
            override fun onActivityResumed(activity: Activity) { onResume() }
            override fun onActivityPaused(activity: Activity) { onPause() }
            override fun onActivityStopped(activity: Activity) {}
            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
            override fun onActivityDestroyed(activity: Activity) {
                //销毁全部对话框
                mDialogQueue.forEach {
                    try {
                        when ( val obj = it.get() ) {
                            is DialogOption -> obj.dismiss()
                            is Dialog -> obj.dismiss()
                            is DialogFragment -> obj.dismiss()
                        }
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }
        })
        return this
    }

    /**
     * 如果添加了 [DialogFragment] 队列，则必须设置FragmentTransaction
     */
    fun setFragmentTransaction(ft: FragmentTransaction) {
        mWrFragmentTransaction = WeakReference( ft )
    }

    /**
     * 获取设置的FragmentTransaction
     */
    fun getFragmentTransaction(): FragmentTransaction? {
        if (mWrFragmentTransaction == null) return null
        var ft: FragmentTransaction?
        try {
            ft = mWrFragmentTransaction!!.get()
            if (ft == null) mWrFragmentTransaction!!.clear()
        } catch (e: Exception) {
            e.printStackTrace()
            ft = null
        }
        return ft
    }

    /**
     * 拦截 [DialogOption] 的显示处理
     */
    fun setOnInterceptShowByDialogOptionListener(listener: Function<DialogOption, Boolean>?) {
        mOnInterceptShowByDialogOptionListener = listener
    }

    /**
     * 拦截 [Dialog] 的显示处理
     */
    fun setOnInterceptShowByDialogListener(listener: Function<Dialog, Boolean>?) {
        mOnInterceptShowByDialogListener = listener
    }

    /**
     * 拦截 [DialogFragment] 的显示处理
     */
    fun setOnInterceptShowByDialogFragmentListener(listener: Function<DialogFragment, Boolean>?) {
        mOnInterceptShowByDialogFragmentListener = listener
    }

    /**
     * 监听队列的剩余数量
     */
    fun setOnDialogQueueChangedListener(listener: Consumer<Int>?) {
        mOnDialogQueueChangedListener = listener
    }

    /**
     * Dialog生命周期
     */
    fun setOnDialogLifecycleListener(listener: OnDialogLifecycleListener?) {
        mOnDialogLifecycleListener = listener
    }

    /**
     * 加入一个Dialog到队列中
     */
    fun addQueue(dop: DialogOption?) {
        dop?.let { dIt ->
            dIt.addOnDismissListener { onDismiss( dIt ) }
            mDialogQueue.add( QueueBean( dIt ) )
            if ( mCurrentQueueBean == null ) next("addQueue")
        }
    }

    /**
     * 加入一个Dialog到队列中
     */
    @JvmOverloads
    fun addQueue(dialog: Dialog?, listener: DialogInterface.OnDismissListener? = null) {
        dialog?.let { dIt ->
            dIt.setOnDismissListener { dialogInterface: DialogInterface ->
                listener?.onDismiss( dialogInterface )
                onDismiss( dialogInterface )
            }
            mDialogQueue.add( QueueBean( dIt ) )
            if ( mCurrentQueueBean == null ) next("addQueue")
        }
    }

    /**
     * 加入一个Dialog到队列中
     */
    @JvmOverloads
    fun addQueue(df: DialogFragment?, listener: DialogInterface.OnDismissListener? = null) {
        df?.let { dIt ->
            val d = dIt.dialog ?: return
            d.setOnDismissListener { dialogInterface: DialogInterface ->
                listener?.onDismiss( dialogInterface )
                onDismiss( dialogInterface )
            }
            mDialogQueue.add( QueueBean( dIt ) )
            if (mCurrentQueueBean == null) next("addQueue")
        }
    }

    /**
     * 暂停队列
     */
    fun pauseQueue() {
        mState = -1 //强制暂停队列
        onPause()
    }

    /**
     * 恢复队列
     */
    fun resumeQueue() {
        mState = 1 //恢复队列
        onResume()
    }

    /**
     * 页面暂停时
     */
    fun onPause() {
        if ( mState != -1 ) mState = 0
        mOnDialogLifecycleListener?.onPause()
    }

    /**
     * 页面恢复时
     */
    fun onResume() {
        if ( mState != -1 ) mState = 1
        mOnDialogLifecycleListener?.onResume()
        //执行下一个在队列中的Dialog
        if ( !lastShowState ) next("resumeQueue")
    }

    /**
     * Dialog是否在队列中
     * @param id    [DialogOption.id]
     * @return      Dialog是否存在于队列中
     */
    fun hasQueue(id: Int): Boolean {
        return findDialog( id ) != null
    }

    /**
     * Dialog是否在队列中
     * @param dop    [DialogOption]
     * @return      Dialog是否存在于队列中
     */
    fun hasQueue(dop: DialogOption?): Boolean {
        return dop != null && hasQueue( dop.id)
    }

    /**
     * Dialog是否在队列中
     * @param dialog    [Dialog]
     * @return          Dialog是否存在于队列中
     */
    fun hasQueue(dialog: Dialog?): Boolean {
        return dialog != null && hasQueue( dialog.hashCode() )
    }

    /**
     * Dialog是否在队列中
     * @param dialog    [Dialog]
     * @return          Dialog是否存在于队列中
     */
    fun hasQueue(dialog: DialogFragment?): Boolean {
        return dialog != null && hasQueue( dialog.hashCode() )
    }

    /**
     * 查找队列中的Dialog
     * @param id    [DialogOption.id] or [Dialog.hashCode] or [DialogFragment.hashCode]
     * @return      [DialogOption]
     */
    private fun find(id: Int): Any? {
        mDialogQueue.forEach { if( it?.id == id ) return it.get() }
        return null
    }

    /**
     * 查找队列中的Dialog
     * @param id    [DialogOption.id] or [Dialog.hashCode]
     * @return      [DialogOption]
     */
    fun findDialogOption(id: Int): DialogOption? { return find( id ) as DialogOption? }

    /**
     * 查找队列中的Dialog
     * @param id    [DialogOption.id] or [Dialog.hashCode]
     * @return      [Dialog]
     */
    fun findDialog(id: Int): Dialog? { return find( id ) as Dialog? }

    /**
     * 查找队列中的Dialog
     */
    fun findDialogFragment(id: Int): DialogFragment? { return find( id ) as DialogFragment? }

    fun size(): Int {
        return mDialogQueue.size
    }

    override fun onDismiss(dialog: DialogInterface?) {
        lastShowState = false
        next("onDismiss")
    }

    private fun next(tag: String?) {
        //检查是否为恢复队列状态
        if ( mState != 1 ) return
        mCurrentQueueBean = poll( tag )
        val obj = mCurrentQueueBean?.get() ?: return
        lastShowState = true
        //DialogOption
        if ( obj is DialogOption ) {
            showByDialogOption( obj )
            return
        }
        //Dialog
        if ( obj is Dialog ) {
            showByDialog( obj )
            return
        }
        //DialogFragment
        if ( obj is DialogFragment ) {
            showByDialogFragment( obj )
            return
        }
    }

    private fun showByDialogOption(dop: DialogOption?) {
        //是否拦截
        if ( mOnInterceptShowByDialogOptionListener?.apply( dop ) == true ) return
        try { dop?.show() } catch (e: Exception) { e.printStackTrace() }
    }

    private fun showByDialog(dialog: Dialog?) {
        //是否拦截
        if ( mOnInterceptShowByDialogListener?.apply( dialog ) == true ) return
        try { dialog?.show() } catch (e: Exception) { e.printStackTrace() }
    }

    private fun showByDialogFragment(df: DialogFragment?) {
        //是否拦截
        if ( mOnInterceptShowByDialogFragmentListener?.apply( df ) == true ) return
        try {
            val ft = getFragmentTransaction()
                ?: throw NullPointerException("show error! ft is null.")
            df?.show( ft, df.tag )
        } catch (e: Exception) {
            e.printStackTrace()
            //show失败之后，通过 Dialog.show 尝试打开
            try { df?.dialog?.show() } catch (e1: Exception) { e1.printStackTrace() }
        }
    }

    private fun poll(tag: String?): QueueBean? {
        val size = mDialogQueue.size
        mOnDialogQueueChangedListener?.accept( size )
        if ( size == 0 ) {
            mCurrentQueueBean = null
            return null
        }
        return mDialogQueue.poll()
    }
}